package edu.bluebeanforum.config;

import org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
import org.springframework.boot.actuate.endpoint.web.*;
import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

// Swagger配置类   可以用来进行接口测试
//http://127.0.0.1:8080/swagger-ui/index.html
// 解决springboot 2.6.0 以上与Springfox 3.0.0不兼容的问题

/**
 * Springfox 是 Swagger 在 Spring 生态系统中的具体实现。Swagger 是一个通用的 API 文档规范和工具，
 * 而 Springfox 则是为了方便在 Spring 项目中使用 Swagger 而开发的库。开发者在 Spring 项目中使用
 * Springfox 可以更轻松地遵循 Swagger 规范，为项目中的 RESTful API 生成高质量的文档和可视化界面。
 *
 *
 * 类级注解
 * @Api：置于控制器类上方，用来描述整个控制器，涵盖名称、描述等信息。
 * @ApiIgnore：标注在类或方法上，使该类或方法不在 Swagger 文档里显示。
 *
 * 方法级注解
 * @ApiOperation：用在控制器方法上，对方法进行详细说明，如功能、返回值等。
 * @ApiResponse：描述单个响应状态码及其对应的消息。
 * @ApiResponses：作为 `@ApiResponse` 的容器注解，可包含多个 `@ApiResponse`，用于描述方法可能出现的多种响应情况。
 *
 * 参数级注解
 * @ApiParam：标注在方法参数处，对参数进行详细描述，包含名称、描述、是否必传、默认值等。
 * @ApiImplicitParam：描述单个参数的信息，涉及参数位置（如 `query`、`path`、`body` 等）、数据类型等。
 * @ApiImplicitParams：`@ApiImplicitParam` 的容器注解，可包含多个 `@ApiImplicitParam`，用于描述方法的多个参数。
 *
 * 模型级注解
 * @ApiModel：标注在模型类上，对模型类进行说明，包括名称、描述等。
 * @ApiModelProperty：标注在模型类的属性上，对属性进行详细描述，如名称、描述、是否必传、示例值等。
 *
 *
 */

@Configuration
// 开启生成api的功能
@EnableOpenApi
public class SwaggerConfig {

    /**
     * Springfox-Swagger基本配置
     */
    @Bean
    public Docket createApi() {
        Docket docket = new Docket(DocumentationType.OAS_30)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("edu.bluebeanforum.controller"))
                .paths(PathSelectors.any())
                .build();
        return docket;

    }

    // 配置API基本信息
    private ApiInfo apiInfo() {
        ApiInfo apiInfo = new ApiInfoBuilder()
                .title("蓝豆论坛系统API")
                .description("蓝豆论坛系统前后端分离API测试")
                .contact(new Contact("Test", "https://baidu.com", "2471097017@qq.com"))
                .version("1.0")
                .build();
        return apiInfo;
    }

    /**
     * 解决SpringBoot 2.6.0以上与Swagger 3.0.0 不兼容的问题
     * 复制即可
     **/
    @Bean
    public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier,
                                                                         ServletEndpointsSupplier servletEndpointsSupplier,
                                                                         ControllerEndpointsSupplier controllerEndpointsSupplier,
                                                                         EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties,
                                                                         WebEndpointProperties webEndpointProperties, Environment environment) {
        List<ExposableEndpoint<?>> allEndpoints = new ArrayList();
        Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
        allEndpoints.addAll(webEndpoints);
        allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());
        allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
        String basePath = webEndpointProperties.getBasePath();
        EndpointMapping endpointMapping = new EndpointMapping(basePath);
        boolean shouldRegisterLinksMapping = this.shouldRegisterLinksMapping(webEndpointProperties, environment,
                basePath);
        return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes,
                corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath),
                shouldRegisterLinksMapping, null);
    }

    private boolean shouldRegisterLinksMapping(WebEndpointProperties webEndpointProperties, Environment environment,
                                               String basePath) {
        return webEndpointProperties.getDiscovery().isEnabled() && (StringUtils.hasText(basePath)
                || ManagementPortType.get(environment).equals(ManagementPortType.DIFFERENT));
    }

}
